home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
mac
/
developm
/
language
/
xlispst.cpt
/
XLisp-Stat ƒ
/
Disk 1
/
statistics.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1990-08-15
|
11KB
|
345 lines
;;;;
;;;; statistics.lsp XLISP-STAT statistics functions
;;;; XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney
;;;; Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz
;;;; You may give out copies of this software; for conditions see the file
;;;; COPYING included with this distribution.
;;;;
(provide "statistics")
;;;;
;;;; Data File Reading
;;;;
(defun count-file-columns (fname)
"Args: (fname)
Returns the number of lisp items on the first nonblank line of file FNAME."
(with-open-file (f fname)
(if f
(let ((line (do ((line (read-line f) (read-line f)))
((or (null line) (< 0 (length line))) line))))
(if line
(with-input-from-string (s line)
(do ((n 0 (+ n 1)) (eof (gensym)))
((eq eof (read s nil eof)) n))))))))
(defvar *xlisptable* *readtable*)
#+(and (not macintosh) dialogs)
(defun open-file-dialog (&optional set)
(get-string-dialog "Enter a data file name:"))
#-dialogs
(defun open-file-dialog (&optional set)
(error "You must provide a file name explicitly"))
(defun read-data-file (&optional (file (open-file-dialog t)))
"Args: (file)
Returns a list of all lisp objects in FILE. FILE can be a string or a symbol,
in which case the symbol'f print name is used."
(if file
(let ((oldtable *readtable*)
(oldbreak *breakenable*)
(eof (gensym)))
(setq *readtable* *xlisptable*)
(setq *breakenable* nil)
(with-open-file (f file)
(if f
(unwind-protect
(do* ((r (read f nil eof) (read f nil eof))
(x (list nil))
(tail x (cdr tail)))
((eq r eof) (cdr x))
(setf (cdr tail) (list r)))
(setq *breakenable* oldbreak)
(setq *readtable* oldtable)))))))
;;; New definition to avoid stack size limit in apply
(defun read-data-columns (&optional (file (open-file-dialog t))
(cols (if file
(count-file-columns file))))
"Args: (&optional file cols)
Reads the data in FILE as COLS columns and returns a list of lists representing the columns."
(if (and file cols)
(transpose (split-list (read-data-file file) cols))))
#+unix
(defun load-data (file)
"Args: (file)
Read in data file from the data examples library."
(if (load (format nil "~aData/~a" *default-path* file))
t
(load (format nil "~aExamples/~a" *default-path* file))))
#+unix
(defun load-example (file)
"Args: (file)
Read in lisp example file from the examples library."
(if (load (format nil "~aExamples/~a" *default-path* file))
t
(load (format nil "~aData/~a" *default-path* file))))
#+macintosh
(defun load-data (s) (require s (concatenate 'string ":Data:" s)))
#+macintosh
(defun load-example (s) (require s (concatenate 'string ":Examples:" s)))
;;;;
;;;; Listing and Saving Variables and Functions
;;;;
(defvar *variables*)
(defvar *ask-on-redefine*)
(defmacro def (symbol value)
"Syntax: (def var form)
VAR is not evaluated and must be a symbol. Assigns the value of FORM to
VAR and adds VAR to the list *VARIABLES* of def'ed variables. Returns VAR.
If VAR is already bound and the global variable *ASK-ON-REDEFINE*
is not nil then you are asked if you want to redefine the variable."
`(unless (and *ask-on-redefine*
(boundp ',symbol)
(not (y-or-n-p "Variable has a value. Redefine?")))
(pushnew ',symbol *variables*)
(setf ,symbol ,value)
',symbol))
(defun variables-list ()
(mapcar #'intern (sort-data (mapcar #'string *variables*))))
(defun variables ()
"Args:()
Returns a list of the names of all def'ed variables to STREAM"
(if *variables*
(mapcar #'intern (sort-data (mapcar #'string *variables*)))))
(defun savevar (vars file)
"Args: (vars file-name-root)
VARS is a symbol or a list of symbols. FILE-NAME-ROOT is a string (or a symbol
whose print name is used) not endinf in .lsp. The VARS and their current values
are written to the file FILE-NAME-ROOT.lsp in a form suitable for use with the
load command."
(let ((f (open (strcat (string file) ".lsp") :direction :output))
(vars (if (consp vars) vars (list vars)))
(oldbreak *breakenable*))
(setq *breakenable* nil)
(unwind-protect
(mapcar
(lambda (x)
(if (objectp (symbol-value x))
(print `(def ,x ,(send (symbol-value x) :save)) f)
(print `(def ,x ',(symbol-value x)) f)))
vars)
(setq *breakenable* oldbreak)
(close f))
vars))
(defun undef (v)
"Args: (v)
If V is the symbol of a defined variable the variable it is unbound and
removed from the list of defined variables. If V is a list of variable
names each is unbound and removed. Returns V."
(dolist (s (if (listp v) v (list v)))
(when (member s *variables*)
(setq *variables* (delete s *variables*))
(makunbound s)))
v)
;;;;
;;;; Basic Summary Statistics
;;;;
(defun standard-deviation (x)
"Args: (x)
Returns the standard deviation of the elements x. Vector reducing."
(let ((n (count-elements x))
(r (- x (mean x))))
(sqrt (* (mean (* r r)) (/ n (- n 1))))))
(defun quantile (x p)
"Args: (x p)
Returns the P-th quantile(s) of sequence X. P can be a number or a sequence."
(let* ((x (sort-data x))
(n (length x))
(np (* p (- n 1)))
(low (floor np))
(high (ceiling np)))
(/ (+ (select x low) (select x high)) 2)))
(defun median (x)
"Args: (x)
Returns the median of the elements of X."
(quantile x 0.5))
(defun interquartile-range (x)
"Args: (number-data)
Returns the interquartile range of the elements of X."
(apply #'- (quantile x '(0.75 0.25))))
(defun fivnum (x)
"Args: (number-data)
Returns the five number summary (min, 1st quartile, medinan, 3rd quartile,
max) of the elements X."
(quantile x '(0 .25 .5 .75 1)))
(defun covariance-matrix (&rest args)
"Args: (&rest args)
Returns the sample covariance matrix of the data columns in ARGS. ARGS may
consist of lists, vectors or matrices."
(let ((columns (apply #'append
(mapcar (lambda (x)
(if (matrixp x) (column-list x) (list x)))
args))))
(/ (cross-product (apply #'bind-columns
(- columns (mapcar #'mean columns))))
(- (length (car columns)) 1))))
;;;;
;;;; Basic Sequence Operations
;;;;
(defun difference (x)
"Args: (x)
Returns differences for a sequence X."
(let ((n (length x)))
(- (select x (iseq 1 (1- n))) (select x (iseq 0 (- n 2))))))
(defun rseq (a b num)
"Args: (a b num)
Returns a list of NUM equally spaced points starting at A and ending at B."
(+ a (* (iseq 0 (1- num)) (/ (- b a) (1- num)))))
;;;;
;;;; Linear Algebra Functions
;;;;
(defun matrix (dim data)
"Args: (dim data)
returns a matrix of dimensions DIM initialized using sequence DATA
in row major order."
(let ((dim (coerce dim 'list))
(data (coerce data 'list)))
(make-array dim :initial-contents (split-list data (nth 1 dim)))))
(defun print-matrix (a &optional (stream *standard-output*))
"Args: (matrix &optional stream)
Prints MATRIX to STREAM in a nice form that is still machine readable"
(unless (matrixp a) (error "not a matrix - ~a" a))
(let ((size (min 15 (max (map-elements #'flatsize a)))))
(format stream "#2a(~%")
(dolist (x (row-list a))
(format stream " (")
(let ((n (length x)))
(dotimes (i n)
(let ((y (aref x i)))
(cond
((integerp y) (format stream "~vd" size y))
((floatp y) (format stream "~vg" size y))
(t (format stream "~va" size y))))
(if (< i (- n 1)) (format stream " "))))
(format stream ")~%"))
(format stream " )~%")
nil))
(defun solve (a b)
"Args: (a b)
Solves A x = B using LU decomposition and backsolving. B can be a sequence
or a matrix."
(let ((lu (lu-decomp a)))
(if (matrixp b)
(apply #'bind-columns
(mapcar #'(lambda (x) (lu-solve lu x)) (column-list b)))
(lu-solve lu b))))
(defun backsolve (a b)
"Args: (a b)
Solves A x = B by backsolving, assuming A is upper triangular. B must be a
sequence. For use with qr-decomp."
(let* ((n (length b))
(sol (make-array n)))
(dotimes (i n)
(let* ((k (- n i 1))
(val (elt b k)))
(dotimes (j i)
(let ((l (- n j 1)))
(setq val (- val (* (aref sol l) (aref a k l))))))
(setf (aref sol k) (/ val (aref a k k)))))
(if (listp b) (coerce sol 'list) sol)))
#|
(defun eigenvalues (a)
"Args: (a)
Returns the singular values of A (the eigen values if A is square and
symmetric"
(coerce (nth 1 (sv-decomp a)) 'list))
(defun eigenvectors (a)
"Args: (a)
Returns the left singular vectors of A (the eigen vectors if A is square and
symmetric"
(column-list (nth 0 (sv-decomp a))))
(defun eigen (a)
"Args: (a)
Returns a list of the list of singular values and a list of left singular
vectors of A (the eigen values and vectors if A is square and symmetric"
(let ((sv (sv-decomp a)))
(list (coerce (nth 1 sv) 'list) (column-list (nth 0 sv)))))
|#
(defun eigenvalues (a)
"Args: (a)
Returns list of eigenvalues of square, symmetric matrix A"
(first (eigen a)))
(defun eigenvectors (a)
"Args: (a)
Returns list of eigenvectors of square, symmetric matrix A"
(second (eigen a)))
;;;
;;; This is a hack, but it will do for now.
;;;
(defun eigen (a)
"Args: (a)
Returns list of list of eigenvalues and list of eigenvectors of square,
symmetric matrix A"
(let* ((n (array-dimension a 0))
(c (second (chol-decomp a)))
(sv (sv-decomp (+ a (diagonal (repeat c n))))))
(list (coerce (- (second sv) c) 'list) (column-list (first sv)))))
(defun accumulate (f s)
"Args: (f s)
Accumulates elements of sequence S using binary function F.
(accumulate #'+ x) returns the cumulative sum of x."
(let* ((result (list (elt s 0)))
(tail result))
(flet ((acc (dummy x)
(rplacd tail (list (funcall f (first tail) x)))
(setf tail (cdr tail))))
(reduce #'acc s))
(if (vectorp s) (coerce result 'vector) result)))
(defun cumsum (x)
"Args: (x)
Returns the cumulative sum of X."
(accumulate #'+ x))
(defun combine (&rest args)
"Args (&rest args)
Returns sequence of elements of all arguments."
(copy-seq (element-seq args)))
(defun lowess (x y &key (f .25) (steps 2) (delta -1) sorted)
"Args: (x y &key (f .25) (steps 2) delta sorted)
Returns (list X YS) with YS the LOWESS fit. F is the fraction of data used for
each point, STEPS is the number of robust iterations. Fits for points within
DELTA of each other are interpolated linearly. If the X values setting SORTED
to T speeds up the computation."
(let ((x (if sorted x (sort-data x)))
(y (if sorted y (select y (order x))))
(delta (if (> delta 0.0) delta (/ (- (max x) (min x)) 50))))
(list x (|base-lowess| x y f steps delta))))